home *** CD-ROM | disk | FTP | other *** search
/ Chip: Internet / Chip Internet.iso / viewer / gsnt / source / gp_mswtx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-12  |  20.0 KB  |  785 lines

  1. /* Copyright (C) 1993  Russell Lang
  2.  
  3. Permission to use, copy, modify, distribute, and sell this
  4. software and its documentation for any purpose is hereby granted
  5. without fee, provided that the above copyright notice and this
  6. permission notice appear in all copies of the software and related
  7. documentation.
  8. */
  9.  
  10. /* gp_mswtx.c */
  11. /*
  12.  * Microsoft Windows 3.n text window for Ghostscript.
  13.  * Original version by Russell Lang
  14.  */
  15.  
  16. #define STRICT
  17. #include "windows_.h"
  18. #include <windowsx.h>
  19. #if WINVER >= 0x030a
  20. #include <commdlg.h>
  21. #include <shellapi.h>
  22. #endif
  23. #include "ctype_.h"
  24. #include "memory_.h"
  25. #include "string_.h"    /* use only far items */
  26. #include <stdlib.h>
  27. #include "dos_.h"
  28.  
  29. #include "gp_mswin.h"
  30. #include "gp_mswtx.h"
  31.  
  32. /* sysmenu */
  33. #define M_COPY_CLIP 1
  34. /* font stuff */
  35. #define TEXTFONTSIZE 9
  36. #define TEXTFONTNAME "Terminal"
  37.  
  38. /* limits */
  39. POINT ScreenMinSize = {16,4};
  40. LRESULT CALLBACK _export WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  41.  
  42. char szNoMemory[] = "out of memory";
  43. LPSTR szTextClass = "gstext_class";
  44.  
  45. void
  46. TextMessage(void)
  47. {
  48.     MSG msg;
  49.     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  50.         {
  51.         TranslateMessage(&msg);
  52.         DispatchMessage(&msg);
  53.         }
  54.     return;
  55. }
  56.  
  57.  
  58. void
  59. CreateTextClass(LPTW lptw)
  60. {
  61. WNDCLASS wndclass;
  62. static BOOL init = FALSE;
  63.     if (init)
  64.         return;
  65.     wndclass.style = CS_HREDRAW | CS_VREDRAW;
  66.     wndclass.lpfnWndProc = WndTextProc;
  67.     wndclass.cbClsExtra = 0;
  68.     wndclass.cbWndExtra = sizeof(void FAR *);
  69.     wndclass.hInstance = lptw->hInstance;
  70.     if (lptw->hIcon)
  71.         wndclass.hIcon = lptw->hIcon;
  72.     else
  73.         wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  74.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  75.     wndclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
  76.     wndclass.lpszMenuName = NULL;
  77.     wndclass.lpszClassName = szTextClass;
  78.     RegisterClass(&wndclass);
  79.     init = TRUE;
  80. }
  81.  
  82.  
  83. /* make text window */
  84. int
  85. TextInit(LPTW lptw)
  86. {
  87.     HMENU sysmenu;
  88.     HGLOBAL hglobal;
  89.     
  90.     if (!lptw->hPrevInstance)
  91.         CreateTextClass(lptw);
  92.  
  93.     if (lptw->KeyBufSize == 0)
  94.         lptw->KeyBufSize = 256;
  95.  
  96.     if (lptw->ScreenSize.x < ScreenMinSize.x)
  97.         lptw->ScreenSize.x = ScreenMinSize.x;
  98.     if (lptw->ScreenSize.y < ScreenMinSize.y)
  99.         lptw->ScreenSize.y = ScreenMinSize.y;
  100.  
  101.     lptw->CursorPos.x = lptw->CursorPos.y = 0;
  102.     lptw->bFocus = FALSE;
  103.     lptw->bGetCh = FALSE;
  104.     lptw->CaretHeight = 0;
  105.     if (!lptw->nCmdShow)
  106.         lptw->nCmdShow = SW_SHOWNORMAL;
  107.  
  108.     hglobal = GlobalAlloc(GHND, lptw->ScreenSize.x * lptw->ScreenSize.y);
  109.     lptw->ScreenBuffer = (BYTE FAR *)GlobalLock(hglobal);
  110.     if (lptw->ScreenBuffer == (BYTE FAR *)NULL) {
  111.         MessageBox((HWND)NULL,szNoMemory,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
  112.         return(1);
  113.     }
  114.     _fmemset(lptw->ScreenBuffer, ' ', lptw->ScreenSize.x * lptw->ScreenSize.y);
  115.     hglobal = GlobalAlloc(LHND, lptw->KeyBufSize);
  116.     lptw->KeyBuf = (BYTE FAR *)GlobalLock(hglobal);
  117.     if (lptw->KeyBuf == (BYTE FAR *)NULL) {
  118.         MessageBox((HWND)NULL,szNoMemory,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
  119.         return(1);
  120.     }
  121.     lptw->KeyBufIn = lptw->KeyBufOut = lptw->KeyBuf;
  122.  
  123.     lptw->hWndText = CreateWindow(szTextClass, lptw->Title,
  124.           WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
  125.           CW_USEDEFAULT, CW_USEDEFAULT,
  126.                   lptw->ScreenSize.x, lptw->ScreenSize.y,
  127.           NULL, NULL, lptw->hInstance, lptw);
  128.     if (lptw->hWndText == (HWND)NULL) {
  129.         MessageBox((HWND)NULL,"Couldn't open text window",(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
  130.         return(1);
  131.     }
  132.     ShowWindow(lptw->hWndText, lptw->nCmdShow);
  133.     sysmenu = GetSystemMenu(lptw->hWndText,0);    /* get the sysmenu */
  134.     AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
  135.     AppendMenu(sysmenu, MF_STRING, M_COPY_CLIP, "Copy to Clip&board");
  136.  
  137.     return(0);
  138. }
  139.  
  140. /* close a text window */
  141. void
  142. TextClose(LPTW lptw)
  143. {
  144.     HGLOBAL hglobal;
  145.  
  146.     /* close window */
  147.     if (lptw->hWndText)
  148.         DestroyWindow(lptw->hWndText);
  149.     TextMessage();
  150.  
  151. #ifdef WIN32
  152. # define SELECTOROF(p)  p
  153. #endif
  154.     hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lptw->ScreenBuffer) );
  155.     if (hglobal) {
  156.         GlobalUnlock(hglobal);
  157.         GlobalFree(hglobal);
  158.     }
  159.     hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lptw->KeyBuf) );
  160.     if (hglobal) {
  161.         GlobalUnlock(hglobal);
  162.         GlobalFree(hglobal);
  163.     }
  164.     lptw->hWndText = (HWND)NULL;
  165. }
  166.     
  167.  
  168. /* Bring Cursor into text window */
  169. void
  170. TextToCursor(LPTW lptw)
  171. {
  172. int nXinc=0;
  173. int nYinc=0;
  174. int cxCursor;
  175. int cyCursor;
  176.     cyCursor = lptw->CursorPos.y * lptw->CharSize.y;
  177.     if ( (cyCursor + lptw->CharSize.y > lptw->ScrollPos.y + lptw->ClientSize.y) 
  178.       || (cyCursor < lptw->ScrollPos.y) ) {
  179.         nYinc = max(0, cyCursor + lptw->CharSize.y - lptw->ClientSize.y) - lptw->ScrollPos.y;
  180.         nYinc = min(nYinc, lptw->ScrollMax.y - lptw->ScrollPos.y);
  181.     }
  182.     cxCursor = lptw->CursorPos.x * lptw->CharSize.x;
  183.     if ( (cxCursor + lptw->CharSize.x > lptw->ScrollPos.x + lptw->ClientSize.x)
  184.       || (cxCursor < lptw->ScrollPos.x) ) {
  185.         nXinc = max(0, cxCursor + lptw->CharSize.x - lptw->ClientSize.x/2) - lptw->ScrollPos.x;
  186.         nXinc = min(nXinc, lptw->ScrollMax.x - lptw->ScrollPos.x);
  187.     }
  188.     if (nYinc || nXinc) {
  189.         lptw->ScrollPos.y += nYinc;
  190.         lptw->ScrollPos.x += nXinc;
  191.         ScrollWindow(lptw->hWndText,-nXinc,-nYinc,NULL,NULL);
  192.         SetScrollPos(lptw->hWndText,SB_VERT,lptw->ScrollPos.y,TRUE);
  193.         SetScrollPos(lptw->hWndText,SB_HORZ,lptw->ScrollPos.x,TRUE);
  194.         UpdateWindow(lptw->hWndText);
  195.     }
  196. }
  197.  
  198. void
  199. NewLine(LPTW lptw)
  200. {
  201.     lptw->CursorPos.x = 0;
  202.     lptw->CursorPos.y++;
  203.     if (lptw->CursorPos.y >= lptw->ScreenSize.y) {
  204.         int i =  lptw->ScreenSize.x * (lptw->ScreenSize.y - 1);
  205.         _fmemmove(lptw->ScreenBuffer, lptw->ScreenBuffer+lptw->ScreenSize.x, i);
  206.         _fmemset(lptw->ScreenBuffer + i, ' ', lptw->ScreenSize.x);
  207.         lptw->CursorPos.y--;
  208.         ScrollWindow(lptw->hWndText,0,-lptw->CharSize.y,NULL,NULL);
  209.         UpdateWindow(lptw->hWndText);
  210.     }
  211.     if (lptw->CursorFlag)
  212.         TextToCursor(lptw);
  213.     TextMessage();
  214. }
  215.  
  216. /* Update count characters in window at cursor position */
  217. /* Updates cursor position */
  218. void
  219. UpdateText(LPTW lptw, int count)
  220. {
  221. HDC hdc;
  222. int xpos, ypos;
  223.     xpos = lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x;
  224.     ypos = lptw->CursorPos.y*lptw->CharSize.y - lptw->ScrollPos.y;
  225.     hdc = GetDC(lptw->hWndText);
  226.     SelectFont(hdc, lptw->hfont);
  227.     TextOut(hdc,xpos,ypos,
  228.         (LPSTR)(lptw->ScreenBuffer + lptw->CursorPos.y*lptw->ScreenSize.x + 
  229.         lptw->CursorPos.x), count);
  230.     (void)ReleaseDC(lptw->hWndText,hdc);
  231.     lptw->CursorPos.x += count;
  232.     if (lptw->CursorPos.x >= lptw->ScreenSize.x)
  233.         NewLine(lptw);
  234. }
  235.  
  236. int
  237. TextPutCh(LPTW lptw, BYTE ch)
  238. {
  239. int pos;
  240.     switch(ch) {
  241.         case '\r':
  242.             lptw->CursorPos.x = 0;
  243.             if (lptw->CursorFlag)
  244.                 TextToCursor(lptw);
  245.             break;
  246.         case '\n':
  247.             NewLine(lptw);
  248.             break;
  249.         case 7:
  250.             MessageBeep(-1);
  251.             if (lptw->CursorFlag)
  252.                 TextToCursor(lptw);
  253.             break;
  254.         case '\t':
  255.             {
  256.             int n;
  257.                 for ( n = 8 - (lptw->CursorPos.x % 8); n>0; n-- )
  258.                     TextPutCh(lptw, ' ');
  259.             }
  260.             break;
  261.         case 0x08:
  262.         case 0x7f:
  263.             lptw->CursorPos.x--;
  264.             if (lptw->CursorPos.x < 0) {
  265.                 lptw->CursorPos.x = lptw->ScreenSize.x - 1;
  266.                 lptw->CursorPos.y--;
  267.             }
  268.             if (lptw->CursorPos.y < 0)
  269.                 lptw->CursorPos.y = 0;
  270.             break;
  271.         default:
  272.             pos = lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
  273.             lptw->ScreenBuffer[pos] = ch;
  274.             UpdateText(lptw, 1);
  275.     }
  276.     return ch;
  277. }
  278.  
  279. void 
  280. TextWriteBuf(LPTW lptw, LPSTR str, int cnt)
  281. {
  282. BYTE FAR *p;
  283. int count, limit;
  284.     while (cnt>0) {
  285.     p = lptw->ScreenBuffer + lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
  286.     limit = lptw->ScreenSize.x - lptw->CursorPos.x;
  287.     for (count=0; (count < limit) && (cnt>0) && (isprint(*str) || *str=='\t'); count++) {
  288.         if (*str=='\t') {
  289.         int n;
  290.         for ( n = 8 - ((lptw->CursorPos.x+count) % 8); (count < limit) & (n>0); n--, count++ ) {
  291.             *p++ = ' ';
  292.         }
  293.         str++;
  294.         count--;
  295.            }
  296.         else {
  297.         *p++ = *str++;
  298.         }
  299.         cnt--;
  300.     }
  301.     if (count>0) {
  302.         UpdateText(lptw, count);
  303.     }
  304.     if (cnt > 0) {
  305.         if (*str=='\n') {
  306.         NewLine(lptw);
  307.         str++;
  308.         cnt--;
  309.         }
  310.         else if (!isprint(*str) && *str!='\t') {
  311.         TextPutCh(lptw, *str++);
  312.         cnt--;
  313.         }
  314.     }
  315.     }
  316. }
  317.  
  318.  
  319. /* TRUE if key hit, FALSE if no key */
  320. int
  321. TextKBHit(LPTW lptw)
  322. {
  323.     return (lptw->KeyBufIn != lptw->KeyBufOut);
  324. }
  325.  
  326. /* get character from keyboard, no echo */
  327. /* need to add extended codes */
  328. int
  329. TextGetCh(LPTW lptw)
  330. {
  331.     int ch;
  332.     TextToCursor(lptw);
  333.     lptw->bGetCh = TRUE;
  334.     if (lptw->bFocus) {
  335.         SetCaretPos(lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x,
  336.             lptw->CursorPos.y*lptw->CharSize.y + lptw->CharAscent 
  337.             - lptw->CaretHeight - lptw->ScrollPos.y);
  338.         ShowCaret(lptw->hWndText);
  339.     }
  340.     do {
  341.         TextMessage();
  342.     } while (!TextKBHit(lptw));
  343.     ch = *lptw->KeyBufOut++;
  344.     if (ch=='\r')
  345.         ch = '\n';
  346.     if (lptw->KeyBufOut - lptw->KeyBuf >= lptw->KeyBufSize)
  347.         lptw->KeyBufOut = lptw->KeyBuf;    /* wrap around */
  348.     if (lptw->bFocus)
  349.         HideCaret(lptw->hWndText);
  350.     lptw->bGetCh = FALSE;
  351.     return ch;
  352. }
  353.  
  354. #if WINVER >= 0x030a
  355. /* Windows 3.1 drag-drop feature */
  356. #ifndef WIN32
  357. static char szFile[80];
  358. #else
  359. static char szFile[1024];
  360. #endif
  361. void
  362. DragFunc(LPTW lptw, HDROP hdrop)
  363. {
  364.     int i, cFiles;
  365.     LPSTR p;
  366.     if ( (lptw->DragPre==(LPSTR)NULL) || (lptw->DragPost==(LPSTR)NULL) )
  367.         return;
  368.     cFiles = DragQueryFile(hdrop, -1, (LPSTR)NULL, 0);
  369.     for (i=0; i<cFiles; i++) {
  370.         DragQueryFile(hdrop, i, szFile, sizeof (szFile));
  371.         for (p=lptw->DragPre; *p; p++)
  372.             SendMessage(lptw->hWndText,WM_CHAR,*p,1L);
  373.         for (p=szFile; *p; p++) {
  374.             if (*p == '\\')
  375.             SendMessage(lptw->hWndText,WM_CHAR,'/',1L);
  376.             else 
  377.             SendMessage(lptw->hWndText,WM_CHAR,*p,1L);
  378.         }
  379.         for (p=lptw->DragPost; *p; p++)
  380.             SendMessage(lptw->hWndText,WM_CHAR,*p,1L);
  381.     }
  382.     DragFinish(hdrop);
  383. }
  384. #endif
  385.  
  386.  
  387. void
  388. TextMakeFont(LPTW lptw)
  389. {
  390.     LOGFONT lf;
  391.     TEXTMETRIC tm;
  392.     LPSTR p;
  393.     HDC hdc;
  394.     
  395.     if ((lptw->fontname[0]=='\0') || (lptw->fontsize==0)) {
  396.         _fstrcpy(lptw->fontname,TEXTFONTNAME);
  397.         lptw->fontsize = TEXTFONTSIZE;
  398.     }
  399.  
  400.     hdc = GetDC(lptw->hWndText);
  401.     _fmemset(&lf, 0, sizeof(LOGFONT));
  402.     _fstrncpy(lf.lfFaceName,lptw->fontname,LF_FACESIZE);
  403.     lf.lfHeight = -MulDiv(lptw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  404.     lf.lfPitchAndFamily = FIXED_PITCH;
  405.     lf.lfCharSet = DEFAULT_CHARSET;
  406.     if ( (p = _fstrstr(lptw->fontname," Italic")) != (LPSTR)NULL ) {
  407.         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
  408.         lf.lfItalic = TRUE;
  409.     }
  410.     if ( (p = _fstrstr(lptw->fontname," Bold")) != (LPSTR)NULL ) {
  411.         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
  412.         lf.lfWeight = FW_BOLD;
  413.     }
  414.     if (lptw->hfont != 0)
  415.         DeleteFont(lptw->hfont);
  416.     lptw->hfont = CreateFontIndirect((LOGFONT FAR *)&lf);
  417.     /* get text size */
  418.     SelectFont(hdc, lptw->hfont);
  419.     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
  420.     lptw->CharSize.y = tm.tmHeight;
  421.     lptw->CharSize.x = tm.tmAveCharWidth;
  422.     lptw->CharAscent = tm.tmAscent;
  423.     if (lptw->bFocus)
  424.         CreateCaret(lptw->hWndText, 0, lptw->CharSize.x, 2+lptw->CaretHeight);
  425.     ReleaseDC(lptw->hWndText, hdc);
  426.     return;
  427. }
  428.  
  429. void
  430. TextCopyClip(LPTW lptw)
  431. {
  432.     int size, count;
  433.     HGLOBAL hGMem;
  434.     LPSTR cbuf, cp;
  435.     TEXTMETRIC tm;
  436.     UINT type;
  437.     HDC hdc;
  438.     int i;
  439.  
  440.     size = lptw->ScreenSize.y * (lptw->ScreenSize.x + 2) + 1;
  441.     hGMem = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)size);
  442.     cbuf = cp = (LPSTR)GlobalLock(hGMem);
  443.     if (cp == (LPSTR)NULL)
  444.         return;
  445.     
  446.     for (i=0; i<lptw->ScreenSize.y; i++) {
  447.         count = lptw->ScreenSize.x;
  448.         _fmemcpy(cp, lptw->ScreenBuffer + lptw->ScreenSize.x*i, count);
  449.         /* remove trailing spaces */
  450.         for (count=count-1; count>=0; count--) {
  451.             if (cp[count]!=' ')
  452.                 break;
  453.             cp[count] = '\0';
  454.         }
  455.         cp[++count] = '\r';
  456.         cp[++count] = '\n';
  457.         cp[++count] = '\0';
  458.         cp += count;
  459.     }
  460.     size = _fstrlen(cbuf) + 1;
  461.     GlobalUnlock(hGMem);
  462.     hGMem = GlobalReAlloc(hGMem, (DWORD)size, GHND | GMEM_SHARE);
  463.     /* find out what type to put into clipboard */
  464.     hdc = GetDC(lptw->hWndText);
  465.     SelectFont(hdc, lptw->hfont);
  466.     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
  467.     if (tm.tmCharSet == OEM_CHARSET)
  468.         type = CF_OEMTEXT;
  469.     else
  470.         type = CF_TEXT;
  471.     ReleaseDC(lptw->hWndText, hdc);
  472.     /* give buffer to clipboard */
  473.     OpenClipboard(lptw->hWndText);
  474.     EmptyClipboard();
  475.     SetClipboardData(type, hGMem);
  476.     CloseClipboard();
  477. }
  478.  
  479.  
  480. /* text window */
  481. LRESULT CALLBACK _export
  482. WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  483. {
  484.     HDC hdc;
  485.     PAINTSTRUCT ps;
  486.     RECT rect;
  487.     int nYinc, nXinc;
  488.     LPTW lptw;
  489.  
  490.     lptw = (LPTW)GetWindowLong(hwnd, 0);
  491.  
  492.     switch(message) {
  493.         case WM_GSVIEW:
  494.             if (wParam != PIPE_DATA)
  495.                 return 0;
  496.             if (pipe_count) {
  497.                 MessageBox(hwnd, "pipe overflow", szAppName, MB_OK);
  498.                 pipe_count = 0;
  499.                 if (pipe_lpbyte != (LPBYTE)NULL)
  500.                     GlobalUnlock(pipe_hglobal);
  501.                 if (pipe_hglobal != (HGLOBAL)NULL)
  502.                     GlobalFree(pipe_hglobal);
  503.             }
  504.             pipe_count = HIWORD(lParam);
  505.             pipe_hglobal = (HGLOBAL)LOWORD(lParam);
  506.             return 0;
  507.         case WM_SYSCOMMAND:
  508.             switch(LOWORD(wParam)) {
  509.                 case M_COPY_CLIP:
  510.                     TextCopyClip(lptw);
  511.                     return 0;
  512.             }
  513.             break;
  514.         case WM_SETFOCUS: 
  515.             lptw->bFocus = TRUE;
  516.             CreateCaret(hwnd, 0, lptw->CharSize.x, 2+lptw->CaretHeight);
  517.             SetCaretPos(lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x,
  518.                 lptw->CursorPos.y*lptw->CharSize.y + lptw->CharAscent
  519.                  - lptw->CaretHeight - lptw->ScrollPos.y);
  520.             if (lptw->bGetCh)
  521.                 ShowCaret(hwnd);
  522.             break;
  523.         case WM_KILLFOCUS: 
  524.             DestroyCaret();
  525.             lptw->bFocus = FALSE;
  526.             break;
  527.         case WM_SIZE:
  528.             lptw->ClientSize.y = HIWORD(lParam);
  529.             lptw->ClientSize.x = LOWORD(lParam);
  530.  
  531.             lptw->ScrollMax.y = max(0, lptw->CharSize.y*lptw->ScreenSize.y - lptw->ClientSize.y);
  532.             lptw->ScrollPos.y = min(lptw->ScrollPos.y, lptw->ScrollMax.y);
  533.  
  534.             SetScrollRange(hwnd, SB_VERT, 0, lptw->ScrollMax.y, FALSE);
  535.             SetScrollPos(hwnd, SB_VERT, lptw->ScrollPos.y, TRUE);
  536.  
  537.             lptw->ScrollMax.x = max(0, lptw->CharSize.x*lptw->ScreenSize.x - lptw->ClientSize.x);
  538.             lptw->ScrollPos.x = min(lptw->ScrollPos.x, lptw->ScrollMax.x);
  539.  
  540.             SetScrollRange(hwnd, SB_HORZ, 0, lptw->ScrollMax.x, FALSE);
  541.             SetScrollPos(hwnd, SB_HORZ, lptw->ScrollPos.x, TRUE);
  542.  
  543.             if (lptw->bFocus && lptw->bGetCh) {
  544.                 SetCaretPos(lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x,
  545.                     lptw->CursorPos.y*lptw->CharSize.y + lptw->CharAscent 
  546.                     - lptw->CaretHeight - lptw->ScrollPos.y);
  547.                 ShowCaret(hwnd);
  548.             }
  549.             return(0);
  550.         case WM_VSCROLL:
  551.             switch(LOWORD(wParam)) {
  552.                 case SB_TOP:
  553.                     nYinc = -lptw->ScrollPos.y;
  554.                     break;
  555.                 case SB_BOTTOM:
  556.                     nYinc = lptw->ScrollMax.y - lptw->ScrollPos.y;
  557.                     break;
  558.                 case SB_LINEUP:
  559.                     nYinc = -lptw->CharSize.y;
  560.                     break;
  561.                 case SB_LINEDOWN:
  562.                     nYinc = lptw->CharSize.y;
  563.                     break;
  564.                 case SB_PAGEUP:
  565.                     nYinc = min(-1,-lptw->ClientSize.y);
  566.                     break;
  567.                 case SB_PAGEDOWN:
  568.                     nYinc = max(1,lptw->ClientSize.y);
  569.                     break;
  570. #ifndef WIN32
  571.                 case SB_THUMBPOSITION:
  572.                     nYinc = LOWORD(lParam) - lptw->ScrollPos.y;
  573.                     break;
  574. #else
  575. #endif
  576.                 default:
  577.                     nYinc = 0;
  578.                 }
  579.             if ( (nYinc = max(-lptw->ScrollPos.y, 
  580.                 min(nYinc, lptw->ScrollMax.y - lptw->ScrollPos.y)))
  581.                 != 0 ) {
  582.                 lptw->ScrollPos.y += nYinc;
  583.                 ScrollWindow(hwnd,0,-nYinc,NULL,NULL);
  584.                 SetScrollPos(hwnd,SB_VERT,lptw->ScrollPos.y,TRUE);
  585.                 UpdateWindow(hwnd);
  586.             }
  587.             return(0);
  588.         case WM_HSCROLL:
  589.             switch(LOWORD(wParam)) {
  590.                 case SB_LINEUP:
  591.                     nXinc = -lptw->CharSize.x;
  592.                     break;
  593.                 case SB_LINEDOWN:
  594.                     nXinc = lptw->CharSize.x;
  595.                     break;
  596.                 case SB_PAGEUP:
  597.                     nXinc = min(-1,-lptw->ClientSize.x);
  598.                     break;
  599.                 case SB_PAGEDOWN:
  600.                     nXinc = max(1,lptw->ClientSize.x);
  601.                     break;
  602. #ifndef WIN32
  603.                 case SB_THUMBPOSITION:
  604.                     nXinc = LOWORD(lParam) - lptw->ScrollPos.x;
  605.                     break;
  606. #else
  607. #endif
  608.                 default:
  609.                     nXinc = 0;
  610.                 }
  611.             if ( (nXinc = max(-lptw->ScrollPos.x, 
  612.                 min(nXinc, lptw->ScrollMax.x - lptw->ScrollPos.x)))
  613.                 != 0 ) {
  614.                 lptw->ScrollPos.x += nXinc;
  615.                 ScrollWindow(hwnd,-nXinc,0,NULL,NULL);
  616.                 SetScrollPos(hwnd,SB_HORZ,lptw->ScrollPos.x,TRUE);
  617.                 UpdateWindow(hwnd);
  618.             }
  619.             return(0);
  620.         case WM_KEYDOWN:
  621.             if (GetKeyState(VK_SHIFT) < 0) {
  622.               switch(wParam) {
  623.                 case VK_HOME:
  624.                     SendMessage(hwnd, WM_VSCROLL, SB_TOP, (LPARAM)0);
  625.                     break;
  626.                 case VK_END:
  627.                     SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, (LPARAM)0);
  628.                     break;
  629.                 case VK_PRIOR:
  630.                     SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)0);
  631.                     break;
  632.                 case VK_NEXT:
  633.                     SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)0);
  634.                     break;
  635.                 case VK_UP:
  636.                     SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)0);
  637.                     break;
  638.                 case VK_DOWN:
  639.                     SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)0);
  640.                     break;
  641.                 case VK_LEFT:
  642.                     SendMessage(hwnd, WM_HSCROLL, SB_LINEUP, (LPARAM)0);
  643.                     break;
  644.                 case VK_RIGHT:
  645.                     SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, (LPARAM)0);
  646.                     break;
  647.               }
  648.             }
  649.             else {
  650.               switch(wParam) {
  651.                 case VK_HOME:
  652.                 case VK_END:
  653.                 case VK_PRIOR:
  654.                 case VK_NEXT:
  655.                 case VK_UP:
  656.                 case VK_DOWN:
  657.                 case VK_LEFT:
  658.                 case VK_RIGHT:
  659.                 case VK_DELETE:
  660.                 { /* store key in circular buffer */
  661.                 long count;
  662.                     count = lptw->KeyBufIn - lptw->KeyBufOut;
  663.                     if (count < 0) count += lptw->KeyBufSize;
  664.                     if (count < lptw->KeyBufSize-2) {
  665.                         *lptw->KeyBufIn++ = 0;
  666.                         if (lptw->KeyBufIn - lptw->KeyBuf >= lptw->KeyBufSize)
  667.                             lptw->KeyBufIn = lptw->KeyBuf;    /* wrap around */
  668.                         *lptw->KeyBufIn++ = HIWORD(lParam) & 0xff;
  669.                         if (lptw->KeyBufIn - lptw->KeyBuf >= lptw->KeyBufSize)
  670.                             lptw->KeyBufIn = lptw->KeyBuf;    /* wrap around */
  671.                     }
  672.                 }
  673.               }
  674.             }
  675.             break;
  676.         case WM_CHAR:
  677.             { /* store key in circular buffer */
  678.             long count;
  679.                 count = lptw->KeyBufIn - lptw->KeyBufOut;
  680.                 if (count < 0) count += lptw->KeyBufSize;
  681.                 if (count < lptw->KeyBufSize-1) {
  682.                     *lptw->KeyBufIn++ = wParam;
  683.                     if (lptw->KeyBufIn - lptw->KeyBuf >= lptw->KeyBufSize)
  684.                         lptw->KeyBufIn = lptw->KeyBuf;    /* wrap around */
  685.                 }
  686.             }
  687.             return(0);
  688.         case WM_PAINT:
  689.             {
  690.             POINT source, width, dest;
  691.             hdc = BeginPaint(hwnd, &ps);
  692.             SelectFont(hdc, lptw->hfont);
  693.             SetMapMode(hdc, MM_TEXT);
  694.             SetBkMode(hdc,OPAQUE);
  695.             GetClientRect(hwnd, &rect);
  696.             source.x = (rect.left + lptw->ScrollPos.x) / lptw->CharSize.x;        /* source */
  697.             source.y = (rect.top + lptw->ScrollPos.y) / lptw->CharSize.y;
  698.             dest.x = source.x * lptw->CharSize.x - lptw->ScrollPos.x;                 /* destination */
  699.             dest.y = source.y * lptw->CharSize.y - lptw->ScrollPos.y;
  700.             width.x = ((rect.right  + lptw->ScrollPos.x + lptw->CharSize.x - 1) / lptw->CharSize.x) - source.x; /* width */
  701.             width.y = ((rect.bottom + lptw->ScrollPos.y + lptw->CharSize.y - 1) / lptw->CharSize.y) - source.y;
  702.             if (source.x < 0)
  703.                 source.x = 0;
  704.             if (source.y < 0)
  705.                 source.y = 0;
  706.             if (source.x+width.x > lptw->ScreenSize.x)
  707.                 width.x = lptw->ScreenSize.x - source.x;
  708.             if (source.y+width.y > lptw->ScreenSize.y)
  709.                 width.y = lptw->ScreenSize.y - source.y;
  710.             /* for each line */
  711.             while (width.y>0) {
  712.                 TextOut(hdc,dest.x,dest.y,
  713.                     (LPSTR)(lptw->ScreenBuffer + source.y*lptw->ScreenSize.x + source.x),
  714.                     width.x);
  715.                 dest.y += lptw->CharSize.y;
  716.                 source.y++;
  717.                 width.y--;
  718.             }
  719.             EndPaint(hwnd, &ps);
  720.             return 0;
  721.             }
  722. #if WINVER >= 0x030a
  723.         case WM_DROPFILES:
  724.             {
  725.             WORD version = LOWORD(GetVersion());
  726.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  727.                 DragFunc(lptw, (HDROP)wParam);
  728.             }
  729.             break;
  730. #endif
  731.         case WM_CREATE:
  732.             {
  733.             RECT crect, wrect;
  734.             TEXTMETRIC tm;
  735.             lptw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
  736.             SetWindowLong(hwnd, 0, (LONG)lptw);
  737.             lptw->hWndText = hwnd;
  738.             /* get character size */
  739.             TextMakeFont(lptw);
  740.             hdc = GetDC(hwnd);
  741.             SelectFont(hdc, lptw->hfont);
  742.             GetTextMetrics(hdc,(LPTEXTMETRIC)&tm);
  743.             lptw->CharSize.y = tm.tmHeight;
  744.             lptw->CharSize.x = tm.tmAveCharWidth;
  745.             lptw->CharAscent = tm.tmAscent;
  746.             ReleaseDC(hwnd,hdc);
  747.             GetClientRect(hwnd, &crect);
  748.             if ( (lptw->CharSize.y*lptw->ScreenSize.y < crect.bottom)
  749.               || (lptw->CharSize.x*lptw->ScreenSize.x < crect.right) ) {
  750.                 /* shrink size */
  751.                 GetWindowRect(lptw->hWndText,&wrect);
  752.                 MoveWindow(lptw->hWndText, wrect.left, wrect.top,
  753.                  wrect.right-wrect.left + (lptw->CharSize.x*lptw->ScreenSize.x - crect.right),
  754.                  wrect.bottom-wrect.top + (lptw->CharSize.y*lptw->ScreenSize.y - crect.bottom),
  755.                  TRUE);
  756.             }
  757. #if WINVER >= 0x030a
  758.             {
  759.             WORD version = LOWORD(GetVersion());
  760.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  761.                 if ( (lptw->DragPre!=(LPSTR)NULL) && (lptw->DragPost!=(LPSTR)NULL) )
  762.                     DragAcceptFiles(hwnd, TRUE);
  763.             }
  764. #endif
  765.             }
  766.             break;
  767.         case WM_CLOSE:
  768.             if (lptw->shutdown)
  769.                 (*(lptw->shutdown))();
  770.             break;
  771.         case WM_DESTROY:
  772. #if WINVER >= 0x030a
  773.             {
  774.             WORD version = LOWORD(GetVersion());
  775.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  776.                 DragAcceptFiles(hwnd, FALSE);
  777.             }
  778. #endif
  779.             if (lptw->hfont != 0)
  780.                 DeleteFont(lptw->hfont);
  781.             break;
  782.     }
  783.     return DefWindowProc(hwnd, message, wParam, lParam);
  784. }
  785.